//
//  CoGeRenderer.m
//  CoGe
//
//  Created by Tamas Nagy on 9/25/10.
//  Copyright 2010 home. All rights reserved.
//

#import "CoGeRenderer.h"
#import "CoGeRenderManager.h"
#import <OpenGL/CGLMacro.h>

@implementation CoGeRenderer


@synthesize compositionFilePath;
@synthesize canUseMSAA;
@synthesize creatorThread;

-(id)initCoGeRendererWithPixelFormat:(NSOpenGLPixelFormat *)format
						   composition:(QCComposition *)composition 
						  shareContext:(NSOpenGLContext *)shareContext
{
	if ((self = [super init]))
	{
        
        markedToRelease = NO;
        
        self.creatorThread = [NSThread currentThread];

        //
		// swap interval does NOT required???
		// because we don't draw to the screen???
		//
		//const GLint swap = 1;
		//[glContext setValues:&swap forParameter:NSOpenGLCPSwapInterval];
       
        colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
        
        texture = 0;
        
        if (composition == nil) {
            NSLog(@"composition invalid!");
        }

        cgl_ctx = [[[CoGeRenderManager sharedManager] glContext] CGLContextObj];


		renderer = [[QCRenderer alloc] initWithCGLContext:cgl_ctx
                                                   pixelFormat:CGLGetPixelFormat(cgl_ctx)
                                                    colorSpace: colorSpace
                                                   composition:composition];

        
		self.canUseMSAA = YES;
        
        return self;

	} else {
    
        NSLog(@"cannot init CoGeRenderer object!");
        
        return nil;
    }
	
}


- (void)lockTexture
{
	CGLLockContext(cgl_ctx);
}

- (void)unlockTexture
{
	CGLUnlockContext(cgl_ctx);
}

//
// Should be careful about calling this method
// since after the first call, it will mark the cached texture to be not available
//
- (GLuint)textureName
{
    if (!texture) {
        
        CGLLockContext(cgl_ctx);
        
      //  CGLSetCurrentContext(cgl_ctx);
        
        // texture / color attachment
        glGenTextures(1, &texture);
       // glEnable(GL_TEXTURE_RECTANGLE_EXT);
        glBindTexture(GL_TEXTURE_RECTANGLE_EXT, texture);
        glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA8, renderSize.width, renderSize.height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
        glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
        
        CGLUnlockContext(cgl_ctx);
        
    }
    
    return texture;
}

-(void)setRenderSize:(NSSize)newSize {


    if (!NSEqualSizes(renderSize, newSize) && texture) {
        CGLLockContext(cgl_ctx);
        glDeleteTextures(1, &texture);
        texture = 0;
        CGLUnlockContext(cgl_ctx);
    }

    
	renderSize = newSize;
}

- (NSSize)textureSize
{
	return renderSize;
}


-(NSSize)renderSize {
	
	return renderSize;
}



#pragma mark Inherated methods 
- (void)renderAtTime:(NSTimeInterval)time withArguments:(NSDictionary *)arguments {
    
  //  NSLog(@"renderer: %@", compositionFilePath);
  //  if (![self.creatorThread isEqualTo:[NSThread currentThread]]) NSLog(@"rendering on the wrong thread!");
    
    CGLLockContext(cgl_ctx);
    [renderer renderAtTime:time arguments:arguments];
    CGLUnlockContext(cgl_ctx);
}

- (QCComposition*) composition {
	return [renderer composition];
}


#pragma mark Protocol methods

- (BOOL)setValue:(id)value forInputKey:(NSString *)key {
  //  if (![self.creatorThread isEqualTo:[NSThread currentThread]]) NSLog(@"setValue on the wrong thread!");
	
	return [renderer setValue:value forInputKey:key];
}

- (id)valueForInputKey:(NSString *)key {
	return [renderer valueForInputKey:key];
}

- (id)valueForOutputKey:(NSString *)key {
	return [renderer valueForOutputKey:key];
}

- (id) valueForOutputKey:(NSString*)key ofType:(NSString*)type {
 //   if (![self.creatorThread isEqualTo:[NSThread currentThread]]) NSLog(@"valueForOutputKey on the wrong thread!");
	return [renderer valueForOutputKey:key ofType:type];
}

- (NSDictionary *)attributes {
	return [renderer attributes]; 
}

- (NSArray *)inputKeys {
	return [renderer inputKeys];
}

- (NSArray *)outputKeys {
	return [renderer outputKeys];
}

- (id) propertyListFromInputValues {
	return [renderer propertyListFromInputValues];
}

- (void) setInputValuesWithPropertyList:(id)plist {
	[renderer setInputValuesWithPropertyList:plist];
}

- (NSMutableDictionary*) userInfo {
	return [renderer userInfo];
}


//a really handy stuff
//which makes our QCRenderer always being released
//on the thread its created
-(void)cleanUpOnRenderingThread {

    if (!markedToRelease) {
        
        markedToRelease = YES;
        
        //waitUntilDone should be NO
        //because creatorThread may not the same than current

        if (self.creatorThread != nil) {
        
            if (![self.creatorThread isEqualTo:[NSThread currentThread]]) {
                
                NSLog(@"releasing QCRenderer in the good thread...");
                
                [self performSelector:@selector(cleanUpRenderer) onThread:self.creatorThread withObject:nil waitUntilDone:NO];
                                
            } else {
                
                [self cleanUpRenderer];
                
            }
            
        } else {
            
            NSLog(@"creatorThread is nil!");
            
            [self cleanUpRenderer];
        
        }
        
        


    }
    
}

-(void)cleanUpRenderer {
    
 //   NSLog(@"cleanUpRenderer start");
    
	[[NSNotificationCenter defaultCenter] removeObserver:self];
    
    CGLLockContext(cgl_ctx);

    if(texture)
    {
        glDeleteTextures(1, &texture);
        texture = 0;
    }
    
    CGLUnlockContext(cgl_ctx);

	
    if (renderer != nil) {
        
        [renderer release];
        renderer = nil;
        
    }
    
    
    if (compositionFilePath != nil) {
        
        [compositionFilePath release];
        compositionFilePath = nil;
        
    }
    
    
    CGColorSpaceRelease(colorSpace);

  //  NSLog(@"cleanUpRenderer done");
    

}

#pragma mark Dealloc

-(void)dealloc {
    
 //   NSLog(@"CoGeRenderer release, retain count: %d", (int)[renderer retainCount]);
	NSLog(@"dealloc CoGeRenderer, finally.");
    
    if (renderer != nil) {
        
        NSLog(@"renderer still not deallocated when deallocating CoGeRenderer...");
        [renderer release];
    }
    
	[super dealloc];
}


@end
